package com.wwinsoft.framework.entity.security;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.OrderBy;
import javax.persistence.Table;
import javax.persistence.Transient;

import org.apache.commons.lang.builder.ToStringBuilder;
import org.codehaus.jackson.annotate.JsonIgnoreProperties;
import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;
import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;

import com.google.common.collect.Lists;
import com.wwinsoft.framework.entity.IdVersionEntity;
import com.wwinsoft.framework.pojo.common.MenuTreeNode;

@Entity
@Table(name = "ACCT_AUTHORITY")
@JsonIgnoreProperties(value = { "parent", "hibernateLazyInitializer", "handler" })
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class Authority extends IdVersionEntity implements MenuTreeNode {

    public static final String TYPE_MENU = "menu";
    public static final String TYPE_SUBMENU = "subMenu";
    public static final String TYPE_ACCESS = "access";


    public static final String AUTHORITY_PREFIX = "A_";

    private String name;

    private double position;
    private String resourceType;
    private Long parentId;

    private List<Resource> resourceList = new ArrayList<Resource>();

    private MenuTreeNode parent;
    private List<MenuTreeNode> children;

    public Authority() {
    }

    public Authority(Long id) {
        this.id = id;
    }

    public Authority(Long id, String name) {
        this.id = id;
        this.name = name;
    }

    @Column(nullable = false, unique = true)
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @ManyToMany
    @JoinTable(name = "ACCT_RESOURCE_AUTHORITY", joinColumns = { @JoinColumn(name = "AUTHORITY_ID") },
               inverseJoinColumns = { @JoinColumn(name = "RESOURCE_ID") })
    @Fetch(FetchMode.SUBSELECT)
    @OrderBy("id")
    @Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
    public List<Resource> getResourceList() {
        return resourceList;
    }

    public void setResourceList(List<Resource> resourceList) {
        this.resourceList = resourceList;
    }


    @Transient
    public String getPrefixedName() {
        return AUTHORITY_PREFIX + name;
    }

    @Override
    public String toString() {
        return ToStringBuilder.reflectionToString(this);
    }

    public double getPosition() {
        return position;
    }

    public void setPosition(double position) {
        this.position = position;
    }

    public String getResourceType() {
        return resourceType;
    }

    public void setResourceType(String resourceType) {
        this.resourceType = resourceType;
    }

    public Long getParentId() {
        return parentId;
    }

    public void setParentId(Long parentId) {
        this.parentId = parentId;
    }

    @Transient
    @Override
    public Long getParentNodeId() {
        return parentId;
    }

    @Transient
    @Override
    public String getNodeName() {
        return name;
    }

    @Transient
    @Override
    public String getNodeType() {
        return resourceType;
    }

    @Transient
    public MenuTreeNode getParent() {
        return parent;
    }

    public void setParent(MenuTreeNode parent) {
        this.parent = parent;
    }

    @Transient
    public List<MenuTreeNode> getChildren() {
        return children;
    }


    public void addChild(MenuTreeNode child) {
        if (children == null) {
            children = new ArrayList<MenuTreeNode>();
        }
        children.add(child);
    }

    @Transient
    @Override
    public Map getAttrMap() {
        HashMap map = new HashMap();
        map.put("revision", getRevision());
        map.put("resourceIds", getResourceIds());
        return map;
    }

    @Transient
    private List<Long> getResourceIds() {
        List<Long> ids = Lists.newArrayList();
        for (Resource resource : resourceList) {
            ids.add(resource.getId());
        }
        return ids;
    }
}
